/*-------------------------------------------------------
   SHOWDIB4.C -- Displays DIB with "all-purpose" palette
                 (c) Charles Petzold, 1998
  -------------------------------------------------------*/

#include <windows.h>
#include "..\set-256color-mode.h"
#include "..\PackeDib.h"
#include "resource.h"

bool g_isHalftoneStretch = false; // Petzold default for ShowDib4

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

TCHAR szAppName[] = TEXT ("ShowDib4") ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	Set_256ColorMode(szAppName);

	if(szCmdLine[0]=='H')
		g_isHalftoneStretch = true;
	else if(szCmdLine[0]=='h')
		g_isHalftoneStretch = false;

	////

	HWND     hwnd ;
	MSG      msg ;
	WNDCLASS wndclass ;

	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = hInstance ;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName  = szAppName ;
	wndclass.lpszClassName = szAppName ;

	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
			szAppName, MB_ICONERROR) ;
		return 0 ;
	}

	hwnd = CreateWindow (szAppName, TEXT ("Show DIB #4: All-Purpose Palette"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, 
		NULL, NULL, hInstance, NULL) ;

	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;

	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

/*------------------------------------------------------------------------
   CreateAllPurposePalette: Creates a palette suitable for a wide variety
          of images; the palette has 247 entries, but 15 of them are 
          duplicates or match the standard 20 colors.
  ------------------------------------------------------------------------*/

HPALETTE CreateAllPurposePalette (void)
{
	HPALETTE hPalette ;
	int          i, incr, R, G, B ;
	LOGPALETTE * plp ;

	plp = (LOGPALETTE*) malloc (sizeof (LOGPALETTE) + 246 * sizeof (PALETTEENTRY)) ;

	plp->palVersion    = 0x0300 ;
	plp->palNumEntries = 247 ;

	// The following loop calculates 31 gray shades, but 3 of them
	//        will match the standard 20 colors

	for (i = 0, G = 0, incr = 8 ; G <= 0xFF ; i++, G += incr)
	{
		plp->palPalEntry[i].peRed   = (BYTE) G ;
		plp->palPalEntry[i].peGreen = (BYTE) G ;
		plp->palPalEntry[i].peBlue  = (BYTE) G ;
		plp->palPalEntry[i].peFlags = 0 ;

		incr = (incr == 9 ? 8 : 9) ;
	}

	// The following loop is responsible for 216 entries, but 8 of 
	//        them will match the standard 20 colors, and another
	//        4 of them will match the gray shades above.

	for (R = 0 ; R <= 0xFF ; R += 0x33)
	for (G = 0 ; G <= 0xFF ; G += 0x33)
	for (B = 0 ; B <= 0xFF ; B += 0x33)
	{
		plp->palPalEntry[i].peRed   = (BYTE) R ;
		plp->palPalEntry[i].peGreen = (BYTE) G ;
		plp->palPalEntry[i].peBlue  = (BYTE) B ;
		plp->palPalEntry[i].peFlags = 0 ;

		i++ ;
	}

	hPalette = CreatePalette (plp) ;

	free (plp) ;
	return hPalette ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static BITMAPINFO * pPackedDib ;
	static HPALETTE     hPalette ;
	static int          cxClient, cyClient ;
	static OPENFILENAME ofn ;
	static TCHAR        szFileName [MAX_PATH], szTitleName [MAX_PATH] ;
	static TCHAR        szFilter[] = TEXT ("Bitmap Files (*.BMP)\0*.bmp\0")
		TEXT ("All Files (*.*)\0*.*\0\0") ;
	HDC                 hdc ;
	PAINTSTRUCT         ps ;

	switch (message)
	{
	case WM_CREATE:
		ofn.lStructSize       = sizeof (OPENFILENAME) ;
		ofn.hwndOwner         = hwnd ;
		ofn.hInstance         = NULL ;
		ofn.lpstrFilter       = szFilter ;
		ofn.lpstrCustomFilter = NULL ;
		ofn.nMaxCustFilter    = 0 ;
		ofn.nFilterIndex      = 0 ;
		ofn.lpstrFile         = szFileName ;
		ofn.nMaxFile          = MAX_PATH ;
		ofn.lpstrFileTitle    = szTitleName ;
		ofn.nMaxFileTitle     = MAX_PATH ;
		ofn.lpstrInitialDir   = NULL ;
		ofn.lpstrTitle        = NULL ;
		ofn.Flags             = 0 ;
		ofn.nFileOffset       = 0 ;
		ofn.nFileExtension    = 0 ;
		ofn.lpstrDefExt       = TEXT ("bmp") ;
		ofn.lCustData         = 0 ;
		ofn.lpfnHook          = NULL ;
		ofn.lpTemplateName    = NULL ;

		// Create the All-Purpose Palette

		hPalette = CreateAllPurposePalette () ;
		return 0 ;

	case WM_SIZE:
		cxClient = LOWORD (lParam) ;
		cyClient = HIWORD (lParam) ;
		return 0 ;

	case WM_COMMAND:
		switch (LOWORD (wParam))
		{
		case IDM_FILE_OPEN:

			// Show the File Open dialog box

			if (!GetOpenFileName (&ofn))
				return 0 ;

			// If there's an existing packed DIB, free the memory

			if (pPackedDib)
			{
				free (pPackedDib) ;
				pPackedDib = NULL ;
			}

			// Load the packed DIB into memory

			SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
			ShowCursor (TRUE) ;

			pPackedDib = PackedDibLoad (szFileName) ;

			ShowCursor (FALSE) ;
			SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

			if (!pPackedDib)
			{
				MessageBox (hwnd, TEXT ("Cannot load DIB file"), 
					szAppName, 0) ;
			}
			InvalidateRect (hwnd, NULL, TRUE) ;
			return 0 ;
		}
		break ;

	case WM_PAINT:
		hdc = BeginPaint (hwnd, &ps) ;

		if (pPackedDib)
		{
			if(g_isHalftoneStretch)
			{
				SetStretchBltMode (hdc, HALFTONE) ;
			}

			SelectPalette (hdc, hPalette, FALSE) ;
			RealizePalette (hdc) ;

			if(g_isHalftoneStretch)
			{	
				// This StretchDIBits call is copied from ShowDib5.cpp .
				// `SetStretchBltMode(hdc, HALFTONE);` is effective only if we call StretchDIBits(),
				// no effect if we call SetDIBitsToDevice().
				StretchDIBits (hdc, 
					0,   
					0,   
					PackedDibGetWidth (pPackedDib), 
					PackedDibGetHeight (pPackedDib),
					0,                            
					0,                            
					PackedDibGetWidth (pPackedDib),
					PackedDibGetHeight (pPackedDib),  
					PackedDibGetBitsPtr (pPackedDib), 
					pPackedDib, 
					DIB_RGB_COLORS, 
					SRCCOPY) ;
			}
			else
			{
				SetDIBitsToDevice (hdc, 
					0,   
					0,   
					PackedDibGetWidth (pPackedDib), 
					PackedDibGetHeight (pPackedDib),
					0,                            
					0,                            
					0,                            
					PackedDibGetHeight (pPackedDib),  
					PackedDibGetBitsPtr (pPackedDib), 
					pPackedDib, 
					DIB_RGB_COLORS) ;
			}
		}
		EndPaint (hwnd, &ps) ;
		return 0 ;

	case WM_QUERYNEWPALETTE:
		hdc = GetDC (hwnd) ;
		SelectPalette (hdc, hPalette, FALSE) ;
		RealizePalette (hdc) ;
		InvalidateRect (hwnd, NULL, TRUE) ;

		ReleaseDC (hwnd, hdc) ;
		return TRUE ;

	case WM_PALETTECHANGED:
		if ((HWND) wParam != hwnd)
			break;

		hdc = GetDC (hwnd) ;
		SelectPalette (hdc, hPalette, FALSE) ;
		RealizePalette (hdc) ;
		UpdateColors (hdc) ;

		ReleaseDC (hwnd, hdc) ;
		break ;

	case WM_DESTROY:
		if (pPackedDib)
			free (pPackedDib) ;

		DeleteObject (hPalette) ;

		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

